package cn.quevo.ucenter.client.service;

import cn.quevo.core.enums.ResultStatusEnum;
import cn.quevo.core.exception.CustomException;
import cn.quevo.core.exception.NotLoginException;
import cn.quevo.core.lang.NumberUtils;
import cn.quevo.core.lang.StringUtils;
import cn.quevo.core.util.BeanUtils;
import cn.quevo.ucenter.client.ClientRestTemplate;
import cn.quevo.ucenter.client.autoconfigure.UcenterProperties;
import cn.quevo.ucenter.client.entity.TokenResponse;
import cn.quevo.ucenter.core.OAuthContext;
import cn.quevo.ucenter.core.enums.GrantTypeEnum;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * 抽象实现
 * 
 * @author July july_sky@foxmail.com
 * @date 2018年3月28日 下午4:23:23
 * @Copyright ©2015-2035 湘豫(北京)科技有限公司. All Rights Reserved.
 * @version 1.0
 */
public abstract class AbstractClientRestService implements ClientRestService{

    @Autowired
    private UcenterProperties ucenterProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public TokenResponse getTokenByPassword(String userName, String password) {
        this.ucenterProperties.validate();
        HttpHeaders headers = new HttpHeaders();
        headers.set(OAuthContext.HeaderType.CONTENT_TYPE, OAuthContext.ContentType.URL_ENCODED);
        headers.set(OAuthContext.HeaderType.AUTHORIZATION, this.encodeClient());
        headers.set(OAuthContext.HeaderType.AJAX,"RestTemplate JSON");
        StringBuilder url = new StringBuilder(this.ucenterProperties.getUrl());
        url.append("/accessToken?").append(OAuthContext.OAUTH_USERNAME).append("=").append(userName);
        url.append("&").append(OAuthContext.OAUTH_GRANT_TYPE).append("=").append(GrantTypeEnum.PASSWORD.getCode());
        url.append("&").append(OAuthContext.OAUTH_PASSWORD).append("=").append(password);
        return this.postForObject(url.toString(), headers);
    }

    @Override
    public TokenResponse getTokenByRefresh(String refreshToken) {
        this.ucenterProperties.validate();
        HttpHeaders headers = new HttpHeaders();
        headers.set(OAuthContext.HeaderType.CONTENT_TYPE, OAuthContext.ContentType.URL_ENCODED);
        headers.set(OAuthContext.HeaderType.AUTHORIZATION, this.encodeClient());
        headers.set(OAuthContext.HeaderType.AJAX,"RestTemplate JSON");
        StringBuilder url = new StringBuilder(this.ucenterProperties.getUrl());
        url.append("&").append(OAuthContext.OAUTH_GRANT_TYPE).append("=").append(GrantTypeEnum.REFRESH_TOKEN.getCode());
        url.append("/accessToken?").append(OAuthContext.OAUTH_REFRESH_TOKEN).append("=").append(refreshToken);
        return this.postForObject(url.toString(), headers);
    }

    private String encodeClient() {
        return "basic "+Base64.encodeBase64String(new String(this.ucenterProperties.getClientId()
                + ":" + this.ucenterProperties.getClientSecret()).getBytes());
    }

    private TokenResponse postForObject(String url, HttpHeaders headers) {
        if (this.restTemplate == null) {
            this.restTemplate = new ClientRestTemplate().getRestTemplate();
        }
        try {
            HttpEntity<String> httpEntity = new HttpEntity<>(headers);
            Object obj = this.restTemplate.postForObject(url, httpEntity, Object.class);
            if (!(obj instanceof Map)) {
                throw new CustomException(ResultStatusEnum.ACCOUNT_PASSWORD_ERROR);
            }
            Map<String, Object> result = (Map<String, Object>) obj;
            if (!StringUtils.isBlank(result.get("status"))) {
                throw new CustomException(NumberUtils.toInt(StringUtils.valueOf(result.get("status")), ResultStatusEnum.ACCOUNT_PASSWORD_ERROR.getCode()), StringUtils.valueOf(result.get("msg")));
            }
            TokenResponse response = new TokenResponse();
            BeanUtils.mapToObject(response, result);
            return response;
        }catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            throw new CustomException(ResultStatusEnum.ACCOUNT_PASSWORD_ERROR);
        }
    }
}
